﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SQLite;
using System.Data;
using System.ComponentModel;

namespace PTCScheduler
{
    /// <summary>
    /// Interaction logic for NewConferenceForm_Page.xaml
    /// </summary>
    public partial class NewConferenceForm_Page : Page
    {
        //SQlite connection for student page
        private SQLiteConnection conn;

        //SQLite connection string
        private String connString = SystemQueries.dbConnString();

        //Arraylist of the teachers to check for conflicts.
        private System.Collections.ArrayList teachersList = new System.Collections.ArrayList();

        //Variable to hold whether counselor is needed or not
        private Boolean CounselorNeededChecked = false;

        //Variable to hold whether conflict was found for any of potential conferences.
        private Boolean OverallConflict;

        //Background worker to handle task of sending emails of confirmed conferences.
        private System.ComponentModel.BackgroundWorker backgroundWorkerEmails = new System.ComponentModel.BackgroundWorker();

        //Consturctor for the new conference form page.
        public NewConferenceForm_Page()
        {
            //Initializes GUI components of new conference form page.
            InitializeComponent();

            //Set contents of txtDate to selected date on Main Window page.
            txtDate.Text = MainWindow_Page.mainSelectedDateAndTime().ToString("yyyy-MM-dd");

            //Bind the teachers to the teacher combobox.
            BindTeacherComboBox();

            //Bind the counselors to the counselor combobox.
            BindCounselorComboBox();

            //Set the background worker event handler for sending emails.
            this.backgroundWorkerEmails.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerEmails_DoWork);
            this.backgroundWorkerEmails.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted);
        }

        //Hides the counselor combobox when unchecked
        private void chkCounselor_Unchecked(object sender, RoutedEventArgs e)
        {
            //Change counselor combobox and label visibility.
            counselorNamelbl.Visibility = Visibility.Hidden;
            counselorComboBox.Visibility = Visibility.Hidden;

            //Set counselor needed check box variable
            CounselorNeededChecked = false;
        }

        //Displays the counselor combobox when checked
        private void chkCounselor_Checked(object sender, RoutedEventArgs e)
        {
            //Change counselor combobox and label visiblity to visible.
            counselorNamelbl.Visibility = Visibility.Visible;
            counselorComboBox.Visibility = Visibility.Visible;

            //Set counselor needed check box variable
            CounselorNeededChecked = true;
        }

        //Method to query and bind the teacher combobox.
        private void BindTeacherComboBox()
        {
            //Connect to the database.
            dbConn();

            //Retrieve the teacher query string from the SystemQueries class and set the
            //teacher combobox contents to teacher names.
            String sql = SystemQueries.teacherComboBox();

            //Create dataset to fill with the results of the query. 
            DataSet ds = new DataSet(); //System.Data assembly

            //User SQLiteDataAdapter to retrieve results. 
            SQLiteDataAdapter da2 = new SQLiteDataAdapter(sql, connString);

            //Fill the dataset with the results. 
            da2.Fill(ds);

            //Set combobox data source to query results.
            teachercomboBox.ItemsSource = ds.Tables[0].DefaultView;

            //Ensure the item source knows which member of the table to search.
            teachercomboBox.DisplayMemberPath = "Teacher";

            //Close connection.
            conn.Close();
            conn.Dispose();
        }

        //Method to query and bind the counselor combobox.
        private void BindCounselorComboBox()
        {
            //Connect to the database.
            dbConn();

            //Retrieve the teacher query string from the SystemQueries class and set the
            //teacher combobox contents to teacher names.
            String sql = SystemQueries.counselorComboBox();

            //Create dataset to fill with the results of the query. 
            DataSet ds = new DataSet(); //System.Data assembly

            //User SQLiteDataAdapter to retrieve results. 
            SQLiteDataAdapter da2 = new SQLiteDataAdapter(sql, connString);

            //Fill the dataset with the results. 
            da2.Fill(ds);

            //Set combobox data source to query results.
            counselorComboBox.ItemsSource = ds.Tables[0].DefaultView;

            //Ensure the item source knows which member of the table to search.
            counselorComboBox.DisplayMemberPath = "Counselor";

            //Close connection.
            conn.Close();
            conn.Dispose();
        }

        //Method to connect to database.
        private void dbConn()
        {
            //Create connection.
            conn = new SQLiteConnection(connString);

            //Open connection
            conn.Open();
        }

        //Add teacher button event handler to add teacher to list box and arraylist
        private void addteacherbtn_Click(object sender, RoutedEventArgs e)
        {
            //Boolean variable for duplicates.
            Boolean isDuplicate = false;

            try
            {
                //Check to ensure a teacher is selected and if they are not selected then catch with null reference exception and
                //else clause.
                if (teachercomboBox.Text != "" || !teachercomboBox.SelectedItem.Equals(null))
                {

                    //Check to ensure string does not equal any strings already in listbox. (Prevents duplicating teachers)
                    foreach (String s in teacherListBox.Items)
                    {
                        //If teacher already exists in listbox break out of 
                        if (teachercomboBox.Text == s)
                        {
                            isDuplicate = true;
                        }
                    }

                    //If teacher is not duplicate then add to listbox.
                    if (isDuplicate == false)
                    {
                        //Add the selected teacher from combobox to the listbox.
                        teacherListBox.Items.Add(teachercomboBox.Text);
                    }
                    else
                    {
                        //Do not add teacher to the listbox.
                    }
                }
                else
                {
                    //Don't add anything to the listbox if nothing is selected from teacher combobox.
                }
            }
            catch (Exception)
            {
                //Don't add anything to the listbox.
            }
        }

        //Remove the teacher from the list box.
        private void removeteacherbtn_Click(object sender, RoutedEventArgs e)
        {
            //Remove selected teacher from listbox.
            teacherListBox.Items.Remove(teacherListBox.SelectedItem);
        }

        //Format date and time back to 24 hour span.
        private String timeFormat(String timeString)
        {
            //Create date time object to format.
            DateTime dt = DateTime.Parse(timeString);

            //Return the desired time string.
            return dt.ToString("HH:mm:ss");
        }

        //Check for that student entered is in the database before scheduling.
        private Boolean IsStudentExists()
        {
            try
            {
                //Connect to database
                dbConn();

                //Retrieve the teacher conflict query string from the SystemQueries class and find the 
                //count for particular teacher in conference table.
                String sql = SystemQueries.studentIDValidQueryString(Convert.ToInt32(txtStudentID.Text));

                //SQLite command to retrieve count(*)
                SQLiteCommand cmd = new SQLiteCommand();
                cmd.CommandText = sql;
                cmd.CommandType = CommandType.Text;
                cmd.Connection = conn;

                //Execute scalar to retrieve and set the value of counselor ID
                Object studentGet = cmd.ExecuteScalar();

                //Convert to integer to retrieve count
                int studentExists = Convert.ToInt32(studentGet);

                //Close and dispose conn.
                conn.Close();
                conn.Dispose();

                //If count is 1 then return true.
                if (studentExists == 1)
                {
                    return true;
                }
                //Otherwise return false.
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        //Pass new conference object in as argument and set variables to user inputs.
        private Conference initializeNewConferenceProperties(String teacherName)
        {
            //Create conference object.
            Conference con = new Conference();

            //If counselor is needed set the variables
            if (CounselorNeededChecked == true)
            {
                //Retrieve variables from GUI components and set them
                con.TeacherName = teacherName;
                con.StudentID = Convert.ToInt32(txtStudentID.Text);
                con.CounselorName = counselorComboBox.Text;
                con.Date = txtDate.Text;
                con.Time = timeFormat(txtTime.Text);
                con.Location = locationtxt.Text;
                con.CounselorNeeded = true;
                con.Comments = txtComments.Text;

                //Return the new conference.
                return con;
            }

            //Retrieve variables from GUI components and set them
            con.TeacherName = teacherName;
            con.StudentID = Convert.ToInt32(txtStudentID.Text);
            con.Date = txtDate.Text;
            con.Time = timeFormat(txtTime.Text);
            con.Location = locationtxt.Text;
            con.CounselorNeeded = false;
            con.Comments = txtComments.Text;

            //Return the new conference.
            return con;
        }

        //BackgroundWorker method that handles sending confirmation emails to teachers.
        //Helps the U.I. become more responsive and not all processes occur on one thread.
        private void backgroundWorkerEmails_DoWork(object sender, DoWorkEventArgs e)
        {
            //Boolean to hold whether to push emails.
            Boolean boolPushEmails = true;

                //Iterate through and insert information.
                foreach (Conference c in teachersList)
                {
                    //Insert the conference information into the database.
                    c.createNewConference();

                    //Check to see if sqlite exception is thrown 
                    if(c.EXSQLite)
                    {
                        boolPushEmails = false;
                        break;
                    }
                }
                
            //If not sqlite exception was thrown then push emails
                if(boolPushEmails)
                {
                    //Push Emails.
                    foreach (Conference c in teachersList)
                    {
                        //Send emails to individual teachers.
                        EmailAutomation email = new EmailAutomation();

                        //Retrieve teacher email.
                        email.getTeacherEmail(c.TeacherID);

                        //Build body of the email.
                        email.buildEmailBody(c.TeacherName, c.buildEmailBodyString());

                        //Send confirmation email to teacher.
                        email.sendEmail();
                    }
                }

                //Clear contents of arraylist.
                teachersList.Clear();
        }//End Do Work event.

        //Method to handle the completion of backgroundworker async which schedules new conference.
        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Don't do anything when process is completed.
        }  

        //Method to hide all labels.
        private void HideAllLabels()
        {
            //Hide labels by default.
            lblValidTeacher.Visibility = Visibility.Hidden;
            lblValidStudentID.Visibility = Visibility.Hidden;
            lblValidTime.Visibility = Visibility.Hidden;
            lblTimeFrame.Visibility = Visibility.Hidden;
        }

        /** The event handler for the schedule button being clicked. 
         * Handles inserting new conferences into database and emailing confirmations. Will
         * utilize BackgroundWorker to handle these costly operations.
         **/
        private void btnSchedule_Click(object sender, RoutedEventArgs e)
        {
            //Hide Labels.
            HideAllLabels();

            //Try catch to catch formatting exceptions.
            try
            {
                //Check to ensure teacher is selected.
                if (teacherListBox.HasItems && IsStudentExists())
                {
                    int n;
                    //Check to ensure student is entered.
                    if (txtStudentID.Text == String.Empty || !(int.TryParse(txtStudentID.Text, out n)))
                    {
                        throw new MissingFieldException();
                    }
                    if (Convert.ToInt32(txtStudentID.Text.ToString()) < 0)
                    {
                        throw new MissingFieldException();
                    }
                    /*(txtDate.Text.Length != 8 || txtDate.Text.IndexOf(":") != 3 || txtDate.Text.LastIndexOf(":") != 6)
                     * Changed to (txtDate.Text.Length != 10 || txtTime.Text.IndexOf(":") != 2 || txtTime.Text.LastIndexOf(":") != 5)
                     * When trying to add a new conference to the db, it kept getting a 'FormatExceptoin Error.
                     * 
                     */
                    //Create date time object to convert the time to 24 hour format for comparison.
                    DateTime dt = DateTime.Parse(txtTime.Text);
                    String TIME24 = dt.ToString("HH:mm:ss");

                    //Retrieve the parsed first two integers from the TIME24 string
                    String tmp = TIME24.Substring(0, 2) + TIME24.Substring(3, 2);
                    int i = Convert.ToInt32(tmp);

                    //Retrieve the parsed first integer to ensure it is 0
                    tmp = txtTime.Text.Substring(0, 1);

                    //Check to ensure correct time format is entered.
                    if (txtDate.Text.Length != 10 || txtTime.Text.IndexOf(":") != 2 || !(int.TryParse(txtStudentID.Text, out n)))
                    {
                        throw new FormatException();
                    }
                    else if (!(txtTime.Text.Contains(" AM")) && !(txtTime.Text.Contains(" PM")))
                    {
                        throw new FormatException();
                    }
                    else if (!(txtTime.Text.EndsWith(" AM")) && !(txtTime.Text.EndsWith(" PM")))
                    {
                        throw new FormatException();
                    }
                    else if (!tmp.Equals("0"))
                    {

                        throw new FormatException();
                    }
                    else if (i < 1400 || i > 1800)
                    {
                        throw new InvalidTimeZoneException();
                    }

                    //Iterate through list box for multiple teachers and add to arraylist.
                    foreach (String s in teacherListBox.Items)
                    {
                        //Add conference objects to the teachers list.
                        teachersList.Add(initializeNewConferenceProperties(s));
                    }

                    //Iterate through list and check for conflicts. If no conflicts then insert details of 
                    //all conferences into database.
                    foreach (Conference c in teachersList)
                    {
                        //Retrieve teacher id
                        c.getTeacherID();

                        //If counselor is needed retrieve counselor id
                        if (c.CounselorNeeded)
                        {
                            c.getCounselorID();
                        }

                        //Check for conflict
                        c.checkConflict();

                        //Check to see if conference has conflict (2 conferences scheduled for same teacher in day.)
                        if (c.Conflict)
                        {
                            //Change state of overall conflict variable to true.
                            OverallConflict = true;
                        }
                    }

                    //Check to see if conference has conflict (2 conferences scheduled for same teacher in day.)
                    if (!OverallConflict)
                    {
                        //Begin process of sending emails.
                        backgroundWorkerEmails.RunWorkerAsync();

                        //Display confirmation window.
                        showConfirmationWindow();

                         //Navigate back to main window page.
                         goHome();
                    }
                    else
                    {
                        //Display conflict window.
                        showConflictWindow();

                        //Navigate back to main window page.
                        goHome();
                    }
                }//End Teacher.text if
                else
                {
                    throw new ArgumentNullException();
                }

            }
            catch (Exception ex)
            {
                if (ex is ArgumentNullException)
                {
                    //Display warning label for teacher
                    lblValidTeacher.Visibility = Visibility.Visible;
                }
                //Determine type of exceptions.
                if (ex is FormatException)
                {
                    //Display time warning label.
                    lblValidTime.Visibility = Visibility.Visible;

                    //Focus back on time textbox
                    txtTime.Focus();
                }
                else if (ex is MissingFieldException)
                {
                    //Display enter student label.
                    lblValidStudentID.Visibility = Visibility.Visible;
                }
                else if (ex is InvalidTimeZoneException)
                {
                    //Display time frame error
                    lblTimeFrame.Visibility = Visibility.Visible;
                }
                else if (ex is SQLiteException)
                {

                }
            }//End try catch

            //Set Overall Conflict back to false.
            OverallConflict = false;
        }
        
        //Method to display conflict window.
        private void showConflictWindow()
        {
            //Show window.
            ConflictWindow window = new ConflictWindow();
            window.Show();
        }

        //Method to display confirmation window.
        private void showConfirmationWindow()
        {
            //Show window.
            ConfirmationWindow window = new ConfirmationWindow();
            window.Show();
        }

        //Method to navigate back to the mainwindowpage.
        private void goHome()
        {
            NavigationService.Navigate(new MainWindow_Page());
        }

    }  
}

